package br.com.games.daedal.imp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import br.com.games.daedal.Box;
import br.com.games.daedal.DaedalTeam;
import br.com.games.daedal.Vertex;
import br.com.games.daedal.ia.Ares;
import br.com.games.hefesto.Move;
import br.com.games.hefesto.Player;
import br.com.games.hefesto.Team;
import br.com.games.hefesto.board.Board;
import br.com.games.hefesto.board.BoardGame;

/**
 * Controla uma partida de Deadal Dots
 * 
 * @since 2013
 * @author <a href="mailto:fernando.schindler@gmail.com">Fernando Schindler</a>
 */
public abstract class Daedal extends BoardGame<Box, Vertex> {

	/**
	 * Criar um controlador de Daedal
	 * 
	 * @param board
	 * @param players
	 */
	public Daedal(DaedalBoard board, Ares... players) {
		super(board, players);
	}

	/**
	 * Mostrar os pontos do vencedor
	 * 
	 * @param player
	 */
	public abstract void showWinner(List<? super DaedalPlayer> player,
			Map<Team, Integer> points);

	/**
	 * Criar um novo jogo
	 * 
	 * @param daedal
	 */
	public abstract void startNewGame(Daedal daedal);

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.games.hefesto.board.BoardGame#reset()
	 */
	@Override
	final public void reset() {
		startNewGame(this);
		super.reset();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.games.hefesto.Game#perform(br.com.games.hefesto.Move)
	 */
	@Override
	final public void perform(Move<Vertex> move) {
		Vertex vertex = move.getMoveable();
		if (!vertex.isActive()) {
			boolean goNext = true;
			vertex.setActive(true);
			vertex.setTeam(getCurrent().getTeam());
			for (Box box : vertex.getOweners()) {
				if (box.isClosed()) {
					box.setOwener(getCurrent().getTeam());
					goNext = false;
				}
			}
			if (goNext)
				nextPlayer();
		} else {
			throw new RuntimeException("vertex is active");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.games.hefesto.Game#undo(br.com.games.hefesto.Move)
	 */
	@Override
	final public void undo(Move<Vertex> move) {
		Vertex vertex = move.getMoveable();
		if (vertex.isActive()) {
			boolean goPrev = true;
			for (Box box : vertex.getOweners()) {
				box.setOwener(DaedalTeam.NONE);
				goPrev = goPrev && !box.isClosed();
			}
			vertex.setActive(false);
			vertex.setTeam(DaedalTeam.NONE);
			if (goPrev)
				prevPlayer();
		} else {
			throw new RuntimeException("vertex is not active");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.games.hefesto.Game#isGameOver()
	 */
	@Override
	final public boolean isGameOver() {
		return getCurrent().getValidMoves(this).size() == 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.games.hefesto.Game#showWinner()
	 */
	@Override
	final public void showWinner() {
		List<Player<? extends Board<Box>, Vertex>> winners = new ArrayList<Player<? extends Board<Box>, Vertex>>();
		Map<Team, Integer> points = new HashMap<Team, Integer>();

		for (Box b : getState().getSquares()) {
			Integer value = points.get(b.getOwner());

			if (null == value) {
				value = b.getValue().intValue();
			} else {
				value = value + b.getValue().intValue();
			}

			points.put(b.getOwner(), value);
		}

		Team winTeam = DaedalTeam.NONE;
		int maxValueInMap = Collections.max(points.values());

		for (Entry<Team, Integer> entry : points.entrySet()) {
			if (entry.getValue() == maxValueInMap) {
				winTeam = entry.getKey();
				break;
			}
		}

		for (Player<? extends Board<Box>, Vertex> p : getPlayers()) {
			if (p.getTeam().equals(winTeam))
				winners.add(p);
		}

		showWinner(winners, points);
	}
}
